/* License Notice:
**
** This program is free software: you can redistribute it and/or modify
**    it under the terms of the GNU General Public License as published by
**    the Free Software Foundation, either version 3 of the License, or
**    (at your option) any later version.
** This program is distributed in the hope that it will be useful,
**   but WITHOUT ANY WARRANTY; without even the implied warranty of
**   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
**   GNU General Public License for more details.
** You should have received a copy of the GNU General Public License
**   along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

/**
 * @file debug.h
 * @author TooOld2Rock'nRoll
 * @date 2023/02
 * @remark Last modified in 2023/02
 * @version 0.1.0
 * @brief Adds trace debug functionality.
 *
 * Works just like printf () and no need to add '\n' in the end of msg.<br>
 * Ex: debug (INFO, "this is my debug msg number %d :D", number);
 *
 * @attention To enable these features, look for ENABLE_DEBUG and ENABLE_OPENGL_DEBUG at config.h
 *
 * @see https://www.khronos.org/opengl/wiki/OpenGL_Error#Meaning_of_errors
 * @see https://www.khronos.org/opengl/wiki/Debug_Output
 *
 * @todo maybe option to write to log file?
 * @todo change the colors of the debug levels, like linux boot sequence.
 */
#ifndef _DEBUG_H_
#define _DEBUG_H_

#ifdef __cplusplus
extern "C" {
#endif


/*---- Includes ----*/
#include <stdio.h>
#include <stdarg.h>

#include "config.h"


/*---- Defines ----*/


/*---- Typedefs ----*/


/*---- Enumerations ----*/
/** @brief The desired debug level to use. */
typedef enum _debug_level_
{
    VERBOSE = 0,///<Lowest debug level, everything will be printed!
    TRACE,      ///<Excludes only the most repetitive messages (like game loop related messages).
    INFO,       ///<Includes debug messages meant for the developers.
    WARNING,    ///<Includes Warning messages, should be given attention but not critical.
    ERROR,      ///<Highest debug level, only critical messages that could impact the program execution.
    _debug_level_max_ ///<just to keep track of enum size!
} debug_level;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
///Private array with names for the debug levels to be printed on messages.
static const char *_debug_level_names[_debug_level_max_] = {"Verbose", "Trace", "Info", "Warning", "Error"};
#pragma GCC diagnostic pop


/*---- Structures ----*/


/*---- Macros ----*/
/**
 * @brief Macro that prints debug messages.
 * @remark It will only be compiled and print messages if ENABLE_DEBUG is true.
 *
 * @param dbg_lvl - debug level, one of debug_level enum options [VERBOSE | TRACE | INFO | WARNING | ERROR].
 * @param msg - the message to print.
 * @param ... - variables to be printed in the message, like printf.
 *
 * @see https://stackoverflow.com/questions/1644868/define-macro-for-debug-printing-in-c
 */
#define _debug(dbg_lvl, msg, ...) \
    do { \
       if (ENABLE_DEBUG) { \
           if (dbg_lvl >= DEBUG_LEVEL) { \
               printf ("[%s] %s(%d): ", _debug_level_names[dbg_lvl], __FILE__, __LINE__); \
               printf (msg, ##__VA_ARGS__); \
               printf ("\n"); }} \
    } while (0)

/**
 * @brief Macro to setup async error message handling for OpenGl operations.
 *
 * @param callback - A callback to send the messages to.
 */
#define _debug_enableGlMessages(callback) \
    if (ENABLE_OPENGL_DEBUG) { \
        glEnable (GL_DEBUG_OUTPUT); \
        glDebugMessageCallback (callback, 0); }


/*---- Function Prototypes ----*/


#ifdef __cplusplus
} //extern "C"
#endif
#endif /* _DEBUG_H_ */

